using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace BBCoder {
	public partial class frmMain: Form {
		public bool previewMode = false;
		private WebBrowser wbPreview = new WebBrowser();


		public frmMain() {
			InitializeComponent();
		}

		private void exitToolStripMenuItem_Click(object sender, EventArgs e) {
			Application.Exit();
		}

		private void undoToolStripMenuItem_Click(object sender, EventArgs e) {
			// Undo the last entry made into the textbox.
			rtxBBCode.Undo();
		}

		private void redoToolStripMenuItem_Click(object sender, EventArgs e) {
			// Redo the previous entry made into the textbox.
			rtxBBCode.Redo();
		}

		private void rtxBBCode_TextChanged(object sender, EventArgs e) {
			// Toggle between whether the text can be undid or redone.
			undoToolStripMenuItem.Enabled = rtxBBCode.CanUndo;
			redoToolStripMenuItem.Enabled = rtxBBCode.CanRedo;
		}

		private void copyToolStripMenuItem_Click(object sender, EventArgs e) {
			// Copy information from the textbox.
			rtxBBCode.Copy();
		}

		private void pasteToolStripMenuItem_Click(object sender, EventArgs e) {
			// Paste information from the clipboard into the textbox.
			rtxBBCode.Paste();
		}

		private void deleteToolStripMenuItem_Click(object sender, EventArgs e) {
			ChangeSelection(string.Empty);
		}

		private void tscbFont_SelectedIndexChanged(object sender, EventArgs e) {
			surround("font", tscbFont.SelectedItem.ToString());
		}

		private void tscbSize_SelectedIndexChanged(object sender, EventArgs e) {
			surround("size", tscbSize.SelectedItem.ToString());
		}

		private void tsbBold_Click(object sender, EventArgs e) {
			surround("b");
		}

		private void tsbItalic_Click(object sender, EventArgs e) {
			surround("i");
		}

		private void tsbUnderline_Click(object sender, EventArgs e) {
			surround("u");
		}

		private void tsbStrikeout_Click(object sender, EventArgs e) {
			surround("s");
		}

		private void tsbColor_Click(object sender, EventArgs e) {
			if(setColor.ShowDialog() == DialogResult.OK) {
				surround("color", "#" + setColor.Color.R.ToString("x2") +
						 setColor.Color.G.ToString("x2") +
						 setColor.Color.B.ToString("x2"));
			}
		}

		private void tsbLink_Click(object sender, EventArgs e) {
			InputBoxResult ibr =
				InputBox.ShowDialog("Please enter the link URL", "http://", this.Text);

			if(ibr.result == DialogResult.OK)
				surround("url", ibr.text);
		}

		private void tsbEmail_Click(object sender, EventArgs e) {
			InputBoxResult ibr =
				InputBox.ShowDialog("Please enter the email address", "", this.Text);

			if(ibr.result == DialogResult.OK)
				surround("email", ibr.text);
		}

		private void tsbImage_Click(object sender, EventArgs e) {
			surround("img");
		}

		private void tsbQuote_Click(object sender, EventArgs e) {
			surround("quote");
		}

		private void tsbCode_Click(object sender, EventArgs e) {
			surround("code");
		}

		private void aboutToolStripMenuItem_Click(object sender, EventArgs e) {
			frmAbout aboutForm = new frmAbout();
			aboutForm.Show();
		}

		private void tsbInline_Click(object sender, EventArgs e) {
			surround("il");
		}

		private void cutToolStripMenuItem_Click(object sender, EventArgs e) {
			rtxBBCode.Cut();
		}

		private void saveToolStripMenuItem_Click(object sender, EventArgs e) {
			if(saveFile.ShowDialog() == DialogResult.OK)
				System.IO.File.WriteAllText(saveFile.FileName, rtxBBCode.Text);
		}

		private void openToolStripMenuItem_Click(object sender, EventArgs e) {
			if(openFile.ShowDialog() == DialogResult.OK)
				rtxBBCode.Text = System.IO.File.ReadAllText(openFile.FileName);
		}

		private void promptSave() {
			if(!String.IsNullOrEmpty(rtxBBCode.Text)) {
				switch(MessageBox.Show("Would you like to save changes?", "Save?",
						MessageBoxButtons.YesNoCancel)) {
					case DialogResult.Yes: {
							if(saveFile.ShowDialog() == DialogResult.OK)
								System.IO.File.WriteAllText(saveFile.FileName, rtxBBCode.Text);
							rtxBBCode.Clear();
							break;
						}

					case DialogResult.No: {
							rtxBBCode.Clear();
							break;
						}
				}
			}
		}

		private void bBCodeFileToolStripMenuItem_Click(object sender, EventArgs e) {
			promptSave();
		}

		private void fromTemplateToolStripMenuItem_Click(object sender, EventArgs e) {
			promptSave();

			frmPickTemplate pickTemplateForm = new frmPickTemplate();
			if(pickTemplateForm.ShowDialog() == DialogResult.OK)
				rtxBBCode.Text = pickTemplateForm.pickTemplateText;
		}

		private void frmMain_FormClosing(object sender, FormClosingEventArgs e) {
			if(!String.IsNullOrEmpty(rtxBBCode.Text)) {
				switch(MessageBox.Show("Would you like to save changes?", "Save?",
						MessageBoxButtons.YesNoCancel)) {
					case DialogResult.Yes: {
							if(saveFile.ShowDialog() == DialogResult.OK)
								System.IO.File.WriteAllText(saveFile.FileName, rtxBBCode.Text);
							rtxBBCode.Clear();
							break;
						}

					case DialogResult.Cancel: {
							e.Cancel = true;
							break;
						}
				}
			}
		}

		private void previewToolStripMenuItem_Click(object sender, EventArgs e) {
			// Show or hide the cursor according to the circumstance.
			if(!previewMode) {
				wbPreview.Parent = this.rtxBBCode.Parent;
				wbPreview.Location = rtxBBCode.Location;
				wbPreview.Size = rtxBBCode.Size;
				wbPreview.DocumentText = bbcodeToHTML(rtxBBCode.Text);
				rtxBBCode.Hide();
				wbPreview.Anchor = (AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom);
				wbPreview.Show();
				previewToolStripMenuItem.Text = "Close Preview";
				previewMode = true;
			} else {
				wbPreview.Hide();
				rtxBBCode.Show();
				previewToolStripMenuItem.Text = "Preview";
				previewMode = false;
			}
		}

		private void tsbNumberedList_Click(object sender, EventArgs e) {
			ChangeSelection("[list=1][*]" + rtxBBCode.SelectedText
				.Replace("\n", "\n[*]") + "\n[/list]");
		}

		private void tsbBulletList_Click(object sender, EventArgs e) {
			ChangeSelection("[list][*]" + rtxBBCode.SelectedText
				.Replace("\n", "\n[*]") + "\n[/list]");
		}

		/// <summary>
		/// Changes selection and reselects it
		/// </summary>
		/// <param name="text">The new text for the selection</param>
		private void ChangeSelection(string text) {
			int selStart = rtxBBCode.SelectionStart;
			rtxBBCode.SelectedText = text;
			rtxBBCode.Select(selStart, text.Length);
		}

		/// <summary>
		/// Surround selection with a tag
		/// </summary>
		/// <param name="tag">Name of the tag</param>
		/// <param name="parameter">Data of the tag</param>
		private void surround(string tag, string parameter) {
			// put equals before parameter, otherwise make it an empty string
			parameter = (parameter != null && parameter.Length > 0) ? "=" + parameter : string.Empty;

			ChangeSelection("[" + tag + parameter + "]"
				+ rtxBBCode.SelectedText + "[/" + tag + "]");
		}

		/// <summary>
		/// Surround selection with a tag
		/// </summary>
		/// <param name="tag">Name of the tag</param>
		private void surround(string tag) {
			surround(tag, null);
		}

		/// <summary>
		/// Convert BB code to HTML
		/// </summary>
		/// <param name="bbcode">BB code</param>
		/// <returns>HTML representation of BB code</returns>
		private string bbcodeToHTML(string bbcode) {
			// The parameterless BBCode identifyers.
			// a.k.a The easy ones.
			string[,] noParamBbcodeHTMLArray = {
                {"[b]", "<b>", "[/b]", "</b>"},
                {"[i]", "<i>", "[/i]", "</i>"},
                {"[u]", "<u>", "[/u]", "</u>"},
                {"[s]", "<s>", "[/s]", "</s>"},
                {"[quote]", "<div style=\"background: #DDDDDD;	border: 1px dotted #000;	border-bottom: 0;	border-left: 4px solid #FF9900;	color: #000;	font-weight: bold;	font-size: 10px;	margin: 8px auto 0 auto;	padding: 3px;\">Quote</div><div style=\"background: #FFFFFF;	border: 1px dotted #000;	border-left: 4px solid #FF9900;		border-top: 0;		color: #000000;	padding: 4px;		margin: 0 auto 8px auto;\">", "[/quote]", "</div>"},
                {"[code]", "<div style=\"background-image: url(" + Environment.CurrentDirectory + "/Images/code_background.bmp);	color: #000;	font-weight: bold;		padding: 3px;       width: 450px;\">CODE</div><div style=\"font-size: 12px !important;        padding: 12px;        background: #FFF;	border: 1px dotted #000;	color: #000000;	font-family: monospace !important;        white-space: nowrap;	overflow: scroll;        max-height: 500px;       width: 450px;\">", "[/code]", "</div>"},
				{"[il]", "<span style=\"border: 1px dotted black; font-family: monospace;\">","[/il]","</span>"},
                {"[inline]", "<span style=\"border: 1px dotted black; font-family: monospace;\">","[/inline]","</span>"}
            };

			// Set the default font to Verdana.
			string tmpString = "<font face=\"Verdana\" size=\"-1\">";

			// Add the BBCode to the string, removing HTML markup.
			tmpString += HTML_Helper.EscapeHTML(bbcode);

			// Turn the new line chars into newlines in HTML.
			tmpString = tmpString.Replace("\n", "\n<br />");

			// Make spaces visible inside [code] tag
			int location = 0;
			int lastend = 0;
			location = tmpString.IndexOf("[code]", lastend);
			while(location >= 0) {
				lastend = tmpString.IndexOf("[/code]", location);

				if(lastend < 0) break;

				string replace = tmpString.Substring(location, lastend - location);
				tmpString = tmpString.Replace(replace, HTML_Helper.PreFormatHTML(replace));

				location = tmpString.IndexOf("[code]", lastend);
			}

			// Loop through and replace all the easy ones.
			for(int j = 0; j <= noParamBbcodeHTMLArray.GetUpperBound(0); j++) {
				for(int i = 0; i < noParamBbcodeHTMLArray.GetUpperBound(1); i++) {
					tmpString = tmpString.Replace(noParamBbcodeHTMLArray[j, i], noParamBbcodeHTMLArray[j, i + 1]);
					// Ignore the next HTML value, and skip to the BBCode.
					i++;
				}
			}

			// Parse the font tag.

			string fontFamily = "";
			int fntFirstInstance = tmpString.IndexOf("[font=");
			int fntLastInstance = 0;
			if(fntFirstInstance > -1) fntLastInstance = tmpString.IndexOf("]", fntFirstInstance);
			else fntLastInstance = -1;

			while(fntFirstInstance > -1 && fntLastInstance > -1) {
				fontFamily = tmpString.Substring(fntFirstInstance + 6, fntLastInstance - (fntFirstInstance + 6));
				tmpString = tmpString.Replace(tmpString.Substring(fntFirstInstance, fntLastInstance - fntFirstInstance + 1), "<font face=\"" + fontFamily + "\">");
				tmpString = tmpString.Replace("[/font]", "</font>");
				fntFirstInstance = tmpString.IndexOf("[font=");
				if(fntFirstInstance > -1) fntLastInstance = tmpString.IndexOf("]", fntFirstInstance);
				else fntLastInstance = -1;
			}

			// Parse the size tag.

			string fontSize = "";
			int sizeFirstInstance = tmpString.IndexOf("[size=");
			int sizeLastInstance = 0;
			if(sizeFirstInstance > -1) sizeLastInstance = tmpString.IndexOf("]", sizeFirstInstance);
			else sizeLastInstance = -1;

			while(sizeFirstInstance > -1 && sizeLastInstance > -1) {
				fontSize = tmpString.Substring(sizeFirstInstance + 6, sizeLastInstance - (sizeFirstInstance + 6));
				tmpString = tmpString.Replace(tmpString.Substring(sizeFirstInstance, sizeLastInstance - sizeFirstInstance + 1), "<font size=\"" + fontSize + "\">");
				tmpString = tmpString.Replace("[/size]", "</font>");
				sizeFirstInstance = tmpString.IndexOf("[size=");
				if(sizeFirstInstance > -1) sizeLastInstance = tmpString.IndexOf("]", sizeFirstInstance);
				else sizeLastInstance = -1;
			}

			// Parse the color tag.

			string fontColor = "";
			int colorFirstInstance = tmpString.IndexOf("[color=");
			int colorLastInstance = 0;
			if(colorFirstInstance > -1) colorLastInstance = tmpString.IndexOf("]", colorFirstInstance);
			else colorLastInstance = -1;

			while(colorFirstInstance > -1 && colorLastInstance > -1) {
				fontColor = tmpString.Substring(colorFirstInstance + 7, colorLastInstance - (colorFirstInstance + 7));
				tmpString = tmpString.Replace(tmpString.Substring(colorFirstInstance, colorLastInstance - colorFirstInstance + 1), "<font color=\"" + fontColor + "\">");
				tmpString = tmpString.Replace("[/color]", "</font>");
				colorFirstInstance = tmpString.IndexOf("[color=");
				if(colorFirstInstance > -1) colorLastInstance = tmpString.IndexOf("]", colorFirstInstance);
				else colorLastInstance = -1;
			}

			// Parse the URL tag

			string url = "";
			int urlFirstInstance = tmpString.IndexOf("[url=");
			int urlLastInstance = 0;
			if(urlFirstInstance > -1) urlLastInstance = tmpString.IndexOf("]", urlFirstInstance);
			else urlLastInstance = -1;

			while(urlFirstInstance > -1 && urlLastInstance > -1) {
				url = tmpString.Substring(urlFirstInstance + 5, urlLastInstance - (urlFirstInstance + 5));
				tmpString = tmpString.Replace(tmpString.Substring(urlFirstInstance, urlLastInstance - urlFirstInstance + 1), "<a href=\"" + url + "\">");
				tmpString = tmpString.Replace("[/url]", "</a>");
				urlFirstInstance = tmpString.IndexOf("[url=");
				if(urlFirstInstance > -1) urlLastInstance = tmpString.IndexOf("]", urlFirstInstance);
				else urlLastInstance = -1;
			}

			// Parse the Email tag

			string mail = "";
			int mailFirstInstance = tmpString.IndexOf("[email]");
			int mailLastInstance = tmpString.IndexOf("[/email]");

			while(mailFirstInstance > -1 && mailLastInstance > -1) {
				mail = tmpString.Substring(mailFirstInstance + 7, mailLastInstance - (mailFirstInstance + 7));
				tmpString = tmpString.Replace(tmpString.Substring(mailFirstInstance, 7), "<a href=\"mailto:" + mail + "\">");
				tmpString = tmpString.Replace("[/email]", "</a>");
				mailFirstInstance = tmpString.IndexOf("[email]");
				mailLastInstance = tmpString.IndexOf("[/email]");
			}

			// Parse the Image tag

			string img = "";
			int imgFirstInstance = tmpString.IndexOf("[img]");
			int imgLastInstance = tmpString.IndexOf("[/img]");

			while(imgFirstInstance > -1 && imgLastInstance > -1) {
				img = tmpString.Substring(imgFirstInstance + 5, imgLastInstance - (imgFirstInstance + 5));
				tmpString = tmpString.Replace(tmpString.Substring(imgFirstInstance, 5), "<img src=\"" + img + "\" alt=\"\">");
				tmpString = tmpString.Replace(img + "[/img]", "");
				imgFirstInstance = tmpString.IndexOf("[img]");
				imgLastInstance = tmpString.IndexOf("[/img]");
			}

			// Parse the bulleted list tag.

			while(tmpString.Contains("[list]")) {
				// We need to find the start and finish of the [list] function
				// so we can start working with it.

				int listPos = tmpString.IndexOf("[list]");
				int endListPos = tmpString.IndexOf("[/list]", listPos) + 7;

				string subStr = tmpString.Substring(listPos, endListPos - listPos);

				// We don't need the original any more, so we shall remove
				// it from the string with the String.Remove method

				tmpString = tmpString.Remove(listPos, endListPos - listPos);

				// Replace the tags with the HTML equivilant, and close
				// the remaining bullet point.
				subStr = subStr.Replace("[list]", "<ul>");
				subStr = subStr.Replace("[/list]", "</li></ul>");

				int countOfBullets = 0;

				while(subStr.Contains("[*]")) {
					if(countOfBullets == 0) {
						int bulletPos = subStr.IndexOf("[*]");
						subStr = subStr.Remove(bulletPos, 3);
						subStr = subStr.Insert(bulletPos, "<li>");
					} else {
						int bulletPos = subStr.IndexOf("[*]");
						subStr = subStr.Remove(bulletPos, 3);
						subStr = subStr.Insert(bulletPos, "</li><li>");
					}
					countOfBullets++;
				}

				// Put the substring back into the original string
				tmpString = tmpString.Insert(listPos, subStr);
			}

			// Parse the numbered list tag.

			while(tmpString.Contains("[list=")) {
				// We need to find the start and finish of the [list] function
				// so we can start working with it.

				int listPos = tmpString.IndexOf("[list=");
				int endListPos = tmpString.IndexOf("[/list]", listPos) + 7;

				string subStr = tmpString.Substring(listPos, endListPos - listPos);

				// We don't need the original any more, so we shall remove
				// it from the string with the String.Remove method

				tmpString = tmpString.Remove(listPos, endListPos - listPos);

				string param = subStr.Substring(subStr.IndexOf('=') + 1,
					subStr.IndexOf(']') - subStr.IndexOf('=') - 1);

				// Replace the tags with the HTML equivilant, and close
				// the remaining bullet point.
				subStr = subStr.Replace("[list=" + param + "]", "<ol type='" + param + "'>");
				subStr = subStr.Replace("[/list]", "</li></ol>");

				int countOfBullets = 0;

				while(subStr.Contains("[*]")) {
					if(countOfBullets == 0) {
						int bulletPos = subStr.IndexOf("[*]");
						subStr = subStr.Remove(bulletPos, 3);
						subStr = subStr.Insert(bulletPos, "<li>");
					} else {
						int bulletPos = subStr.IndexOf("[*]");
						subStr = subStr.Remove(bulletPos, 3);
						subStr = subStr.Insert(bulletPos, "</li><li>");
					}
					countOfBullets++;
				}

				// Put the substring back into the original string
				tmpString = tmpString.Insert(listPos, subStr);
			}

			// Close the default font tag.
			tmpString += "</font>";
			// Return the HTML version of the BBCode.
			return tmpString;
		}
	}
}